package com.allen.app.common.utils;

import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import lombok.extern.slf4j.Slf4j;
import reactor.core.Exceptions;

@Slf4j
public class Try {

    public static <T> FaultTolerant<T> run(Supplier supplier) {
        return new FaultTolerant<>(supplier);
    }

    public static <T, R> Function<T, R> fun(UncheckedFunction<T, R> mapper) {
        Objects.requireNonNull(mapper);
        return t -> {
            try {
                return mapper.apply(t);
            } catch (Throwable throwable) {
                throw new RuntimeException(Exceptions.unwrap(throwable));
            }
        };
    }

    public static <T> Predicate<T> bool(UncheckedPredicate<T> mapper) {
        Objects.requireNonNull(mapper);
        return t -> {
            try {
                return mapper.test(t);
            } catch (Throwable throwable) {
                throw new RuntimeException(Exceptions.unwrap(throwable));
            }
        };
    }

    public static <T> Consumer<T> consume(UncheckedConsumer<T> mapper) {
        Objects.requireNonNull(mapper);
        return t -> {
            try {
                mapper.accept(t);
            } catch (Throwable throwable) {
                throw new RuntimeException(Exceptions.unwrap(throwable));
            }
        };
    }

    /**
     * 检查异常信息并返回.
     * @param supplier  supplier  
     * @return T 
     * @author Limiaojun
     * @date 2020/3/14 0014 13:01
     */ 
    public static <T> T unchecked(UncheckedSupplier<T> supplier) {
        try {
            return supplier.get();
        } catch (Throwable throwable) {
            throw new RuntimeException(Exceptions.unwrap(throwable));
        }
    }

    /**
     * 检查异常信息但是不返回.
     * @param supplier  supplier
     * @author Limiaojun
     * @date 2020/3/14 0014 13:00
     */
    public static void unchecked(TryCatch<Void> supplier) {
        try {
            supplier.accept();
        } catch (Throwable throwable) {
            throw new RuntimeException(Exceptions.unwrap(throwable));
        }
    }

    /**
    * 捕获异常信息并打印.
    * @param tryCatch  tryCatch
    * @author Limiaojun
    * @date 2020/1/10 14:53
    */
    public static void tryCatch(TryCatch<Void> tryCatch) {
        try {
            tryCatch.accept();
        } catch (Throwable throwable) {
            log.error("Try.tryCatch.exception:\t ",throwable);
//            throw new RuntimeException(Exceptions.unwrap(throwable));
        }
    }

    /**
    * 捕获异常信息返回默认值.
    * @param supplier  supplier
    * @param defaultObj  defaultObj
    * @return T
    * @author Limiaojun
    * @date 2020/1/10 14:52
    */
    public static <T> T tryCatch(UncheckedSupplier<T> supplier,T defaultObj) {
        try {
            return supplier.get();
        } catch (Throwable throwable) {
//            log.error("Try.tryCatch.exception:\t ",throwable);
            return defaultObj;
        }
    }

    public static void unchecked(Supplier<Void> supplier) {
        try {
            supplier.get();
        } catch (Throwable throwable) {
            throw new RuntimeException(Exceptions.unwrap(throwable));
        }
    }

    @SafeVarargs
    public static <T> T ignored(Supplier<T> supplier, Class<? extends Throwable>... ignoreTypes) {
        try {
            return supplier.get();
        } catch (Throwable t) {
            List<Class<? extends Throwable>> types = Arrays.asList(ignoreTypes);
            if (types.size() > 0 && !types.contains(t.getClass())) {
                throw t;
            }
            return null;
        }
    }

    @FunctionalInterface
    public interface UncheckedPredicate<T> {
        boolean test(T t) throws Exception;
    }

    @FunctionalInterface
    public interface UncheckedFunction<T, R> {
        R apply(T t) throws Exception;
    }

    @FunctionalInterface
    public interface UncheckedConsumer<T> {
        void accept(T t) throws Exception;
    }

    @FunctionalInterface
    public interface UncheckedSupplier<T> {
        T get() throws Throwable;
    }

    @FunctionalInterface
    public interface TryCatch<Void> {
        void accept() throws Throwable;
    }

    public static class FaultTolerant<T> {
        private Object result;
        private Throwable throwable;
        private boolean hasError;

        private FaultTolerant(Supplier supplier) {
            try {
                this.result = supplier.get();
            } catch (Throwable t) {
                this.throwable = Exceptions.unwrap(t);
                this.hasError = true;
            }
        }

        @SuppressWarnings("unchecked")
        public T orElse(T other) {
            return hasError ? other : (T) this.result;
        }

        public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
            if (hasError) {
                throw exceptionSupplier.get();
            }
            return orElse(null);
        }

        public T orElseCatch(Consumer<? super Throwable> exceptionConsumer) {
            if (hasError) {
                exceptionConsumer.accept(this.throwable);
            }
            return orElse(null);
        }
    }

//    public static void main(String[] args) {
//        Try.unchecked(()->{
//            SortDto sortUtils = new SortDto("a","b");
//            ClassUtil.buildEmptyStrToNull(sortUtils);
//
//        });
////        System.out.println(Try.tryCatch(()->Integer.valueOf("aaa"),1));
////        Try.unchecked(()->{
////            Integer.valueOf("aaa");
////            return SUCCESS;
////        });
//    }
//
//    @Data
//    public static class AA{
//        private Integer a;
//        private String b;
//    }
}


